#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UTable.Input;
using UTable.Objects.Handlers;
using UTable.Input.MultiTouch;
using System.Windows;

namespace UTable.Objects.Policies
{
    public class ObjectLayoutPolicy: LayoutPolicy
    {
        private class ObjectInfo
        {
            public SingleFingerHandler Handler;

            public Point FingerDownPosition;

            public Point ObjectStartPosition;
        }

        private int currentMaxZIndex = 0;

        private Dictionary<IObject, ObjectInfo> handlerMap = new Dictionary<IObject, ObjectInfo>();

        private Dictionary<SingleFingerHandler, IObject> objectMap = new Dictionary<SingleFingerHandler, IObject>();

        public ObjectLayoutPolicy(IObject target, object param)
            : base(target, param)
        {

        }

        void OnSingleFingerDown(SingleFingerHandler sender, UTable.Input.MultiTouch.FingerEventArgs args)
        {
            IObject obj = objectMap[sender];
            handlerMap[obj].FingerDownPosition = args.GlobalPosition;
            handlerMap[obj].ObjectStartPosition = obj.Position;
        }

        void OnSingleFingerMove(SingleFingerHandler sender, UTable.Input.MultiTouch.FingerEventArgs args)
        {
            double margin = 20;
            IObject obj = objectMap[sender];
            Point p = handlerMap[obj].ObjectStartPosition + (args.GlobalPosition - handlerMap[obj].FingerDownPosition);
            Rect bound = new Rect(new Point(-obj.Width + margin, -obj.Height + margin),
                new Size(Target.Width + obj.Width - margin * 2, Target.Height + obj.Height - margin*2));
            if (bound.Contains(p))
                obj.Position = p;
        }

        void OnSingleFingerUp(SingleFingerHandler sender, UTable.Input.MultiTouch.FingerEventArgs args)
        {

        }

        /// <summary>
        /// Called when a sub-object received input
        /// </summary>
        public override void OnInputReceived(IObject obj, InputEventArgs args)
        {
            if (args is MultiTouchEventArgs)
            {
                if (handlerMap.ContainsKey(obj))
                {
                    handlerMap[obj].Handler.OnMultiTouch(args as MultiTouchEventArgs);
                }
            }
        }

        /// <summary>
        /// called when a sub-object is inserted into current object
        /// </summary>
        public override void OnObjectInserted(IObject obj)
        {
            // Put the incoming obj at the center
            obj.Position = new System.Windows.Point((Target.Width - obj.Width) / 2, (Target.Height - obj.Height) / 2);
            obj.ZIndex = currentMaxZIndex++;

            SingleFingerHandler handler = new SingleFingerHandler(obj);
            handler.SingleFingerDown += new SingleFingerEventHandler(OnSingleFingerDown);
            handler.SingleFingerMove += new SingleFingerEventHandler(OnSingleFingerMove);
            handler.SingleFingerUp += new SingleFingerEventHandler(OnSingleFingerUp);

            ObjectInfo info = new ObjectInfo();
            info.Handler = handler;
            handlerMap.Add(obj, info);
            objectMap.Add(handler, obj);
        }

        /// <summary>
        /// called when a sub-object is closed
        /// </summary>
        public override void OnObjectClosed(IObject obj)
        {
            OnObjectRemoved(obj);
        }

        public override void OnObjectRemoved(IObject obj)
        {
            if (handlerMap.ContainsKey(obj))
            {
                SingleFingerHandler handler = handlerMap[obj].Handler;
                handler.SingleFingerDown -= OnSingleFingerDown;
                handler.SingleFingerMove -= OnSingleFingerMove;
                handler.SingleFingerUp -= OnSingleFingerUp;
                handlerMap.Remove(obj);
                objectMap.Remove(handler);
            }
        }
    }
}
